﻿#include <QDebug>

#include "LightController.h"

namespace dgkoma {

const int timeout_ms = 20;

static char char2ASCII_Hex(char x)
{
    x = x % 16;
    if(x < 10)
    {
        return '0' + x;
    }
    else
    {
        x = x - 10;
        return 'A' + x;
    }
}

static int ASCII_Hex2Int(char x)
{
    if(x >= '0' && x <= '9') return x - '0';
    if(x >= 'A' && x <= 'F') return x - 'A' + 0x0A;

    return -1;
}

static int Hex2Int(char x[3])
{
    int a1 = ASCII_Hex2Int(x[0]);
    int a2 = ASCII_Hex2Int(x[1]);
    int a3 = ASCII_Hex2Int(x[2]);

    return a1 * 256 + a2 * 16 + a3;
}
bool LightController::open(QString comm)
{
    if(!m_serialPort) return false;
    //if(!m_serialPort->isWritable()) return false;
    m_serialPort->setPortName(comm);
    if(m_serialPort->open(QIODevice::ReadWrite))
    {
        m_serialPort->setBaudRate(QSerialPort::Baud9600);
        m_serialPort->setDataBits(QSerialPort::Data8);
        m_serialPort->setParity(QSerialPort::NoParity);
        m_serialPort->setStopBits(QSerialPort::OneStop);
        m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
        m_serialPort->clearError();
        m_serialPort->clear();
        qDebug() << "LightController open";
        return true;
    }
    return false;
}

bool LightController::close()
{
    if(!m_serialPort)
    {
        return false;
    }
    m_serialPort->close();
    return true;
}

LightController::LightController(QObject *parent) : QObject(parent)
{
    m_serialPort = new QSerialPort("COM6", this);
}

bool LightController::turn_on(uint8_t ch)
{
    if(!m_serialPort) return false;
    if(!m_serialPort->isWritable()) return false;
    char cmd[] = "$1100000";
    cmd[1] = '1' + ch;
    char x = cmd[0] ^ cmd[1] ^ cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5];
    cmd[7] = char2ASCII_Hex(x);
    cmd[6] = char2ASCII_Hex(x >> 4);

    m_serialPort->clearError();
    m_serialPort->clear();

    m_serialPort->write(cmd, 8);

    if( m_serialPort->waitForReadyRead(timeout_ms) )
    {
        int len = m_serialPort->read(cmd, 8);
        if( len != 1 || cmd[0] != '$')
        {
            return false;
        }
        return true;
    }
    return false;
}

bool LightController::setLight(uint8_t ch, int level)
{
    if(!m_serialPort) return false;
    if(!m_serialPort->isWritable()) return false;
    char cmd[] = "$3100000";
    cmd[2] = '1' + ch;   
    cmd[5] = char2ASCII_Hex(level % 16);
    cmd[4] = char2ASCII_Hex(level / 16);
    cmd[3] = char2ASCII_Hex(level / 256);

    char x = cmd[0] ^ cmd[1] ^ cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5];
    cmd[7] = char2ASCII_Hex(x);
    cmd[6] = char2ASCII_Hex(x >> 4);

    m_serialPort->clearError();
    m_serialPort->clear();

    m_serialPort->write(cmd, 8);
    if( m_serialPort->waitForReadyRead(timeout_ms) )
    {
        int len = m_serialPort->read(cmd, 8);
        if( len != 1 || cmd[0] != '$') return false;
        return true;
    }
    return false;
}

bool LightController::readLight(uint8_t ch, uint8_t &level)
{
    level = 0;
    if(!m_serialPort) return false;
    if(!m_serialPort->isWritable()) return false;
    char cmd[] = "$4100000";
    cmd[2] = '1' + ch;
    char x = cmd[0] ^ cmd[1] ^ cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5];
    cmd[7] = char2ASCII_Hex(x);
    cmd[6] = char2ASCII_Hex(x >> 4);

    m_serialPort->clearError();
    m_serialPort->clear();

    m_serialPort->write(cmd, 8);

    QByteArray buffer;
    while (buffer.size() < 8)
    {
        if( !m_serialPort->waitForReadyRead(timeout_ms) )
        {
            return false;
        }
        buffer += m_serialPort->readAll();
    }
    if( buffer[0] != '$' && buffer[1] != '4' && buffer[2] != cmd[2])
    {
        return false;
    }
    char hex[3];
    hex[0] = buffer[3];
    hex[1] = buffer[4];
    hex[2] = buffer[5];

    level = Hex2Int(hex);

    return false;
}

bool LightController::turn_off(uint8_t ch)
{
    if(!m_serialPort) return false;
    if(!m_serialPort->isWritable()) return false;
    char cmd[] = "$2100000";
    cmd[2] = '1' + ch;
    char x = cmd[0] ^ cmd[1] ^ cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5];
    cmd[7] = char2ASCII_Hex(x);
    cmd[6] = char2ASCII_Hex(x >> 4);

    m_serialPort->clearError();
    m_serialPort->clear();

    m_serialPort->write(cmd, 8);
    if( m_serialPort->waitForReadyRead(timeout_ms) )
    {
        int len = m_serialPort->read(cmd, 8);
        if( len != 1 || cmd[0] != '$') return false;
        return true;
    }
    return false;
}

}
